/**
 * @class Prototype UI Extension creates a tab system within the specified
 * container.  
 * @author embrace.toolkit
 * @public
 * @version $Id: TableSorter.js 78 2009-09-29 07:15:26Z embrace.toolkit $
 */
eui.TabSystem = Class.create({
	/** @lends eui.TabSystem */
	/**
	 * referenced Dom element
	 * @private
	 */
	element: false,
	/**
	 * Contains all tabs within the tab system, on close tab has to be deleted 
	 * from this collection.
	 * @type Array
	 * @private
	 */
	tabCollection: false,
	/**
	 * Constructor, creates the tab system.
	 * 
	 * @param eui.TabSystem.Options parameters The options to setup instance.
	 * @public 
	 */
	initialize: function(parameters) {
		if(!parameters.element)
			throw("NullPointerException: Element could not be null.");
		
		this.element = parameters.element;
	},
	/**
	 * Displays the given tab, if already in tab only activates.
	 * 
	 * @param eui.TabSystem.Tab tab the tab object to display
	 * @public
	 */
	showTab: function(tab) {
		if(!this.tabCollection)
			this.tabCollection = $H();

		if(!this.tabCollection.index(tab.url)) {
			this.tabCollection.set(tab.title, tab.url);
			try {
				this.loadTab(tab);
			}catch(exc) {
				console.error("LoadTab failded: %o", exc);
			}
			$(this.element).fire("tab:added", { "tab": tab});
		}
		
		$(this.element).select(".tabContent").invoke("hide");
		$(this.element).select(".tabContent[tabTitle=" + tab.title + "]").invoke("show");
		$(this.element).select(".tabButton").invoke("removeClassName", "active");
		$(this.element).select(".tabButton[tabTitle=" + tab.title + "]").invoke("addClassName", "active");
		
		$(this.element).fire("tab:show", { "tab": tab });
	},
	/**
	 * Loads the tabs content from tab.url via ajax.
	 * @param eui.TabSystem.Tab tab the tab to load
	 * @private
	 */
	loadTab: function(tab) {
		var tabContent = new Element("div", {
			tabTitle: tab.title
		}); 
		tabContent.addClassName("tabContent");
		$(this.element).select("#tabContent").first().insert(tabContent);
		
		var tabButton = new Element("li", {
			tabTitle: tab.title
		});
		tabButton.addClassName("tabButton");
		tabButton.update(tab.title);
		tabButton.observe("click", this.showTabClicked.bind(this));
		
		var tabCloser = new Element("em", {
			title: "close tab: " + tab.title
		});
		tabCloser.addClassName("tabCloser");
		tabCloser.update("&nbsp;");
		tabCloser.observe("click", this.closeTab.bind(this));
		
		tabButton.insert(tabCloser);
		$(this.element).select("#tabs>ul").first().insert(tabButton);
		
		new Ajax.Updater(tabContent, tab.url, {
			onComplete: function() {
				$(this.element).fire("tab:loaded", { "tab": tab });
			}.bind(this)
		});
	},
	/**
	 * <p>Notified when tab will be closed.</p>
	 * 
	 * <p><strong>Attention: on close the TabSystem will automatically
	 * activate the last tab in order of the TabCollection.</strong></p>
	 * @param Event clickEvent the notified event.
	 * @private
	 * @event click
	 */
	closeTab: function(clickEvent) {
		var el = clickEvent.findElement().up();
		var tabToClose = el.readAttribute("tabTitle");
		$(this.element).select("[tabTitle=" + tabToClose + "]").invoke("remove");
		this.tabCollection.unset(tabToClose);
		this.showLastTab();
		clickEvent.stop();
	},
	/**
	 * Activates the last tab contained in tabCollection.
	 * @public
	 */
	showLastTab: function() {
		if(this.tabCollection.size() <= 0)
			return;
		
		var lastTab = $(this.element).select(
			"#tabs>ul>li[tabTitle]"
		).last().readAttribute("tabTitle");
		
		this.showTab({
			title: lastTab,
			url: this.tabCollection.get(lastTab)
		});
	},
	/**
	 * Notified when tabButton is clicked.
	 * @param Event clickEvent the notified event.
	 * @private
	 * @event click
	 */
	showTabClicked: function (clickEvent) {
		var el = clickEvent.findElement();
		this.showTab({
			title: el.readAttribute("tabTitle"),
			url: this.tabCollection.get(
					el.readAttribute("tabTitle")
			)
		});
	}
});

/**
 * @class Parameters for creating a tab system object.
 * @public
 * @example
 * <p>You can youse the classical OOP way like this:
 * 	<code>
 *var tabOptions = new eui.TabSystem.Options();
 *tabOptions.element = "tabDiv";
 * 	</code>
 * Or the inline way like:
 * 	<code>
 *var tabOptions = {
 *	element: "tabDiv"
 *};
 * 	</code>
 * </p>
 * <p>Both ways are functional, because {@link eui.TabSystem.Options} is 
 * only an Interface how to setup {@link eui.TabSystem}.
 * </p>
 */
eui.TabSystem.Options = Class.create({
	/** @lends eui.TabSystem.Options */ 
	/**
	 * The referenced DOM element ID.
	 * @public
	 */
	element: false
});

/**
 * Creates a eui.TabSystem.Tab object.
 * @sees eui.TabSystem.Tab#initialize
 * @class Parameters for creating a tab system object.
 * @public
 * @example
 * <p>You can youse the classical OOP way like this:
 * 	<code>
 *var tab = new eui.TabSystem.Tab();
 *tab.title = "Title of Tab";
 *tab.url = "/tabContent/content.php";
 * 	</code>
 * Or the inline way like:
 * 	<code>
 *var tab = {
 *	title: "Title of Tab",
 *	url: "/tabContent/content.php"
 *};
 * 	</code>
 * </p>
 * <p>Both ways are functional, because {@link eui.TabSystem.Tab} is 
 * only an Interface how to setup {@link eui.TabSystem}.
 */
eui.TabSystem.Tab = Class.create({
	/** @lends eui.TabSystem.Tab */ 
	/**
	 * Title of the tab, displayed in eui.TabSystem.
	 * @private
	 * @type String
	 */
	title: false,
	/**
	 * Url to load content for Tab from.
	 * @private
	 * @type String
	 */
	url: false,
	/**
	 * Constructor creates the Object.
	 * 
	 * @param String title The displayed title of the tab.
	 * @param String url the URL to load content from.
	 * @public
	 */
	initialize: function(title, url) {
		this.title = title;
		this.url = url;
	}
});